#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/spinlock.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/delay.h>

static dev_t at24c02_devid;                  
static struct cdev at24c02_cdev;           
static struct class *at24c02_class;         
static struct device *at24c02_device;
static int at24c02_major = 0;
static int at24c02_minor = 0;

static struct i2c_client *at24c02_i2c_client = NULL;

static int at24c02_read_block_data(char *buf, int size)
{
    struct i2c_msg msg[2];
    unsigned char msg_buf[2];
    char mem_reg = 0x0; // mem基地址
    int ret = 0;

    /* 第一个write msg通讯 */
    
    /* 一个W/R的I2c协议够成一个msg */
    /* 设置i2c_msg地址 */
    msg[0].addr = at24c02_i2c_client->addr;
    /* 设置i2c_msg write */
    msg[0].flags = 0;
    /* 设置msg_buf的值 */
    msg_buf[0] = mem_reg;
    msg[0].buf = msg_buf;
    /* 设置msg_buf长度 */
    msg[0].len = 1; 

    /* 第二个read msg通讯 */
    
    /* 一个W/R的I2c协议够成一个msg */
    /* 设置i2c_msg地址 */
    msg[1].addr = at24c02_i2c_client->addr;
    /* 设置i2c_msg write */
    msg[1].flags = I2C_M_RD;
    /* 设置读的msg */
    msg[1].buf = buf;
    /* 设置msg_buf长度 */
    msg[1].len = size;

    ret = i2c_transfer(at24c02_i2c_client->adapter, msg, 2);
    if (ret != 2) {
        pr_err("at24c02_write_byte_data faield\n");
        return -EBUSY;
    }

    return 0;
}

static int at24c02_write_byte_data(char *buf, int size)
{
    struct i2c_msg msg;
    unsigned char msg_buf[2];
    char mem_reg = 0x0; // mem基地址
    char *buf_str = buf;
    int ret = 0;

    while (*buf_str) {
        /* 一个W/R的I2c协议够成一个msg */
        /* 设置i2c_msg地址 */
        msg.addr = at24c02_i2c_client->addr;
        /* 设置i2c_msg write */
        msg.flags = 0;
        /* 设置msg_buf的值 */
        msg_buf[0] = mem_reg;
        msg_buf[1] = *buf_str;
        msg.buf = msg_buf;
        /* 设置msg_buf长度 */
        msg.len = 2;

        /* 调用传输函数 */
        ret = i2c_transfer(at24c02_i2c_client->adapter, &msg, 1);
        if (ret != 1) {
            pr_err("at24c02_write_byte_data faield\n");
            return -EBUSY;
        }
        // 等待10ms
        mdelay(20);
        buf_str++;
        mem_reg++;
    }

    /* 一个W/R的I2c协议够成一个msg */
    /* 设置i2c_msg地址 */
    msg.addr = at24c02_i2c_client->addr;
    /* 设置i2c_msg write */
    msg.flags = 0;
    /* 设置msg_buf的值 */
    msg_buf[0] = mem_reg;
    msg_buf[1] = '\0';
    msg.buf = msg_buf;
    /* 设置msg_buf长度 */
    msg.len = 2;

    /* 调用传输函数 */
    ret = i2c_transfer(at24c02_i2c_client->adapter, &msg, 1);
    if (ret != 1) {
        pr_err("at24c02_write_byte_data faield\n");
        return -EBUSY;
    }
    // 等待10ms
    mdelay(20);

    return 0;
}

static int at24c02_read(struct file *file, char __user *buf, size_t size, loff_t * offset)
{
    int ret = 0;
    char buf_str[32];
    at24c02_read_block_data(buf_str, size);
    
    // 成功返回0, 失败，返回有多少个Bytes未完成copy
    ret = copy_to_user(buf, buf_str, size);
    if (ret) {
        pr_err("copy_to_user mem_addr failed\n");
        return size - ret;
    }

    return size;
}

static int at24c02_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    int ret = 0;

    /* 从APP复制数据 */
    char buf_str[32];
    
    memset(buf_str, 0, 32);
    ret = copy_from_user(buf_str, buf, size);
    if (ret) {
        pr_err("copy_from_user mem_addr failed\n");
        return size - ret;
    }

    at24c02_write_byte_data(buf_str, size);

    return size;
}

static struct file_operations at24c02_fops = {
    .owner  = THIS_MODULE,
    .read   = at24c02_read,
    .write  = at24c02_write, 
};


/**
 * 当驱动和硬件信息匹配成功之后，就会调用probe函数，驱动所有的资源的注册和初始化全部放在probe函数中
 */
static int at24c02_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;
    /* 1.保存i2c_client,存储有i2c_adapter */
    at24c02_i2c_client = client;

    pr_info("at24c02_probe\n");
    
    /* 4. 动态分配字符设备号 */
    alloc_chrdev_region(&at24c02_devid, 0, 1, "at24c02");
    at24c02_major = MAJOR(at24c02_devid);
    at24c02_minor = MINOR(at24c02_devid);

    /* 5.初始化字符设备，添加字符设备 */
    cdev_init(&at24c02_cdev, &at24c02_fops);
    cdev_add(&at24c02_cdev, at24c02_devid, 1);


    /* 6.创建类,它会在sys目录下创建/sys/class/dtsled这个类  */
    at24c02_class = class_create(THIS_MODULE, "at24c02");
    if (IS_ERR(at24c02_class)) {
        dev_err(&client->dev, "create class failed\n");
        ret = PTR_ERR(at24c02_class);
        return -ret;
    }

    /* 7. 在/sys/class/led下创建dtsled设备，然后mdev通过这个自动创建/dev/dtsled这个设备节点 */
    at24c02_device = device_create(at24c02_class, NULL, at24c02_devid, NULL, "at24c02");
    if (IS_ERR(at24c02_device)) {
         dev_err(&client->dev, "create device failed\n");
         ret = PTR_ERR(at24c02_device);
        return -ret;
    }

    return 0;
}

/**
 * 硬件信息被移除了，或者驱动被卸载了，全部要释放，释放资源的操作就放在该函数中
 */
static int at24c02_remove(struct i2c_client *client)
{
    /* 注销类、以及类设备 */
    device_destroy(at24c02_class, at24c02_devid);
    class_destroy(at24c02_class);

    /* 删除设备，卸载注册的设备编号 */
    cdev_del(&at24c02_cdev);
    unregister_chrdev_region(at24c02_devid, 1);

    return 0;
}

/**
 * 用于设备树匹配
 */
static const struct of_device_id at24c02_dt_match[] = {
    { .compatible = "atmel,at24c02", },
    { /* END OF LIST */ },
};

/**
 * 用于client_dev匹配
*/
static const struct i2c_device_id at24c02_id_table[] = {
    { "at24c02", 0 },
    { /* END OF LIST */ }
};


static struct i2c_driver at24c02_i2c_drv = {
    .driver	= {
        .name	= "at2440 drv",
        .of_match_table = at24c02_dt_match,
        .owner	= THIS_MODULE,
    },
    .probe		= at24c02_probe,
    .remove		= at24c02_remove,
    .id_table	= at24c02_id_table,
};

static int at2440_init(void)
{
    int ret = 0;
    ret = i2c_add_driver(&at24c02_i2c_drv);
    if (ret != 0) {
        pr_err("%s: at2440 driver err, error=%d\n", __func__, ret);
    }

    return ret;
}

/**
 * i2c驱动模块出口
 */
static void at2440_exit(void)
{
    i2c_del_driver(&at24c02_i2c_drv);
}

module_init(at2440_init);
module_exit(at2440_exit);

MODULE_AUTHOR("huang");
MODULE_DESCRIPTION("jz2440 at24c02 i2c transfer driver");
MODULE_LICENSE("GPL");




